#![allow(non_upper_case_globals)]
use std::ops::Deref;
use std::ptr;

use super::foundation::*;
use super::graphics_types::*;

pub type CTFontDescriptorRef = CFValueRef;
pub struct CTFontDescriptor(pub CFValue);
impl Deref for CTFontDescriptor {
	type Target = CFValue;
	fn deref(&self) -> &Self::Target {
		&self.0
	}
}
impl From<CTFontDescriptor> for CFValue {
	fn from(value: CTFontDescriptor) -> Self {
		value.0
	}
}
impl CTFontDescriptor {
	pub fn from_attributes(attributes: &CFDictionary) -> CTFontDescriptor {
		unsafe {
			let result: CTFontDescriptorRef = CTFontDescriptorCreateWithAttributes(attributes.as_ref());
			Self(CFValue::create_rule(result))
		}
	}
}

pub type CTFontRef = CFValueRef;
pub struct CTFont(pub CFValue);
impl Deref for CTFont {
	type Target = CFValue;
	fn deref(&self) -> &Self::Target {
		&self.0
	}
}
impl From<CTFont> for CFValue {
	fn from(value: CTFont) -> Self {
		value.0
	}
}
impl CTFont {
	pub fn from_descriptor(desc: &CTFontDescriptor, pt_size: f64) -> Self {
		unsafe {
			let font_ref = CTFontCreateWithFontDescriptor(desc.as_ref(), pt_size as CGFloat, ptr::null());
			Self(CFValue::create_rule(font_ref))
		}
	}
	pub fn ui_for_language(ui_type: CTFontUIFontType, size: CGFloat, language: CFStringRef) -> Self {
		unsafe {
			let font_ref = CTFontCreateUIFontForLanguage(ui_type, size, language);
			Self(CFValue::create_rule(font_ref))
		}
	}
	pub fn for_string(&self, string: CFStringRef, range: CFRange) -> Self {
		unsafe {
			let result = CTFontCreateForString(self.as_ref(), string, range);
			Self(CFValue::create_rule(result))
		}
	}
	pub fn unique_id(&self) -> Option<String> {
		unsafe {
			let value = CTFontCopyName(self.as_ref(), kCTFontUniqueNameKey);
			if value.is_null() {
				return None;
			}
			let s = CFString(CFValue::get_rule(value as CFValueRef));
			Some(s.to_string())
		}
	}
	pub fn family(&self) -> Option<String> {
		unsafe {
			let value = CTFontCopyName(self.as_ref(), kCTFontFamilyNameKey);
			if value.is_null() {
				return None;
			}
			let s = CFString(CFValue::get_rule(value as CFValueRef));
			Some(s.to_string())
		}
	}
	pub fn font_path(&self) -> Option<std::path::PathBuf> {
		unsafe {
			let value = CTFontCopyAttribute(self.as_ref(), kCTFontURLAttribute);
			if value.is_null() {
				return None;
			}
			let url = CFURL(CFValue::get_rule(value as CFValueRef));
			url.to_path()
		}
	}
}

pub const kCTFontClassMaskShift: u32 = 28;
pub type CTFontSymbolicTraits = u32;
pub const kCTFontItalicTrait: CTFontSymbolicTraits = 1 << 0;
pub const kCTFontBoldTrait: CTFontSymbolicTraits = 1 << 1;
pub const kCTFontExpandedTrait: CTFontSymbolicTraits = 1 << 5;
pub const kCTFontCondensedTrait: CTFontSymbolicTraits = 1 << 6;
pub const kCTFontMonoSpaceTrait: CTFontSymbolicTraits = 1 << 10;
pub const kCTFontVerticalTrait: CTFontSymbolicTraits = 1 << 11;
pub const kCTFontUIOptimizedTrait: CTFontSymbolicTraits = 1 << 12;
pub const kCTFontColorGlyphsTrait: CTFontSymbolicTraits = 1 << 13;
pub const kCTFontClassMaskTrait: CTFontSymbolicTraits = 15 << kCTFontClassMaskShift;

pub type CTFontUIFontType = u32;
// kCTFontNoFontType: CTFontUIFontType = -1;
pub const kCTFontUserFontType: CTFontUIFontType = 0;
pub const kCTFontUserFixedPitchFontType: CTFontUIFontType = 1;
pub const kCTFontSystemFontType: CTFontUIFontType = 2;
pub const kCTFontEmphasizedSystemFontType: CTFontUIFontType = 3;
pub const kCTFontSmallSystemFontType: CTFontUIFontType = 4;
pub const kCTFontSmallEmphasizedSystemFontType: CTFontUIFontType = 5;
pub const kCTFontMiniSystemFontType: CTFontUIFontType = 6;
pub const kCTFontMiniEmphasizedSystemFontType: CTFontUIFontType = 7;
pub const kCTFontViewsFontType: CTFontUIFontType = 8;
pub const kCTFontApplicationFontType: CTFontUIFontType = 9;
pub const kCTFontLabelFontType: CTFontUIFontType = 10;
pub const kCTFontMenuTitleFontType: CTFontUIFontType = 11;
pub const kCTFontMenuItemFontType: CTFontUIFontType = 12;
pub const kCTFontMenuItemMarkFontType: CTFontUIFontType = 13;
pub const kCTFontMenuItemCmdKeyFontType: CTFontUIFontType = 14;
pub const kCTFontWindowTitleFontType: CTFontUIFontType = 15;
pub const kCTFontPushButtonFontType: CTFontUIFontType = 16;
pub const kCTFontUtilityWindowTitleFontType: CTFontUIFontType = 17;
pub const kCTFontAlertHeaderFontType: CTFontUIFontType = 18;
pub const kCTFontSystemDetailFontType: CTFontUIFontType = 19;
pub const kCTFontEmphasizedSystemDetailFontType: CTFontUIFontType = 20;
pub const kCTFontToolbarFontType: CTFontUIFontType = 21;
pub const kCTFontSmallToolbarFontType: CTFontUIFontType = 22;
pub const kCTFontMessageFontType: CTFontUIFontType = 23;
pub const kCTFontPaletteFontType: CTFontUIFontType = 24;
pub const kCTFontToolTipFontType: CTFontUIFontType = 25;
pub const kCTFontControlContentFontType: CTFontUIFontType = 26;

#[link(kind = "framework", name = "CoreText")]
extern "C" {
	pub static kCTFontSymbolicTrait: CFStringRef;
	pub static kCTFontWeightTrait: CFStringRef;
	pub static kCTFontWidthTrait: CFStringRef;
	pub static kCTFontSlantTrait: CFStringRef;

	//  CTFontDescriptor.h
	pub static kCTFontURLAttribute: CFStringRef; // value: CFURLRef
	pub static kCTFontNameAttribute: CFStringRef; // value: CFStringRef
	pub static kCTFontDisplayNameAttribute: CFStringRef; // value: CFStringRef
	pub static kCTFontFamilyNameAttribute: CFStringRef; // value: CFStringRef
	pub static kCTFontStyleNameAttribute: CFStringRef; // value: CFStringRef
	pub static kCTFontTraitsAttribute: CFStringRef;
	pub static kCTFontVariationAttribute: CFStringRef;
	pub static kCTFontSizeAttribute: CFStringRef;
	pub static kCTFontMatrixAttribute: CFStringRef;
	pub static kCTFontCascadeListAttribute: CFStringRef;
	pub static kCTFontCharacterSetAttribute: CFStringRef;
	pub static kCTFontLanguagesAttribute: CFStringRef;
	pub static kCTFontBaselineAdjustAttribute: CFStringRef;
	pub static kCTFontMacintoshEncodingsAttribute: CFStringRef;
	pub static kCTFontFeaturesAttribute: CFStringRef;
	pub static kCTFontFeatureSettingsAttribute: CFStringRef;
	pub static kCTFontFixedAdvanceAttribute: CFStringRef;
	pub static kCTFontOrientationAttribute: CFStringRef;
	pub static kCTFontFormatAttribute: CFStringRef;
	pub static kCTFontRegistrationScopeAttribute: CFStringRef;
	pub static kCTFontPriorityAttribute: CFStringRef;
	pub static kCTFontEnabledAttribute: CFStringRef;
	// CTFont.h
	pub static kCTFontCopyrightNameKey: CFStringRef;
	pub static kCTFontFamilyNameKey: CFStringRef;
	pub static kCTFontSubFamilyNameKey: CFStringRef;
	pub static kCTFontStyleNameKey: CFStringRef;
	pub static kCTFontUniqueNameKey: CFStringRef;
	pub static kCTFontFullNameKey: CFStringRef;
	pub static kCTFontVersionNameKey: CFStringRef;
	pub static kCTFontPostScriptNameKey: CFStringRef;
	pub static kCTFontTrademarkNameKey: CFStringRef;
	pub static kCTFontManufacturerNameKey: CFStringRef;
	pub static kCTFontDesignerNameKey: CFStringRef;
	pub static kCTFontDescriptionNameKey: CFStringRef;
	pub static kCTFontVendorURLNameKey: CFStringRef;
	pub static kCTFontDesignerURLNameKey: CFStringRef;
	pub static kCTFontLicenseNameKey: CFStringRef;
	pub static kCTFontLicenseURLNameKey: CFStringRef;
	pub static kCTFontSampleTextNameKey: CFStringRef;
	pub static kCTFontPostScriptCIDNameKey: CFStringRef;

	pub fn CTFontCreateForString(currentFont: CTFontRef, string: CFStringRef, range: CFRange) -> CTFontRef;
	pub fn CTFontCreateWithFontDescriptor(descriptor: CTFontDescriptorRef, size: CGFloat, matrix: *const CGAffineTransform) -> CTFontRef;
	pub fn CTFontCreateUIFontForLanguage(uiType: CTFontUIFontType, size: CGFloat, language: CFStringRef) -> CTFontRef;
	pub fn CTFontCopyFontDescriptor(font: CTFontRef) -> CTFontDescriptorRef;
	pub fn CTFontCopyAttribute(font: CTFontRef, attribute: CFStringRef) -> CFRef;
	pub fn CTFontCopyName(font: CTFontRef, nameKey: CFStringRef) -> CFStringRef;

	pub fn CTFontDescriptorCreateWithAttributes(attributes: CTFontDescriptorRef) -> CTFontDescriptorRef;
	pub fn CTFontDescriptorCopyAttribute(descriptor: CTFontDescriptorRef, attribute: CFStringRef) -> CFRef;

	pub fn CTFontManagerCopyAvailableFontFamilyNames() -> CFArrayRef;
	pub fn CTFontManagerCopyAvailablePostScriptNames() -> CFArrayRef;
}
